import axios from 'axios'
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useUserStore } from '@/stores/user'
import router from '@/router'
import type { ApiResponse } from '@/types/api'

// ==================== Token刷新队列机制 ====================
// 用于防止多个401请求同时触发token刷新

// 是否正在刷新token
let isRefreshing = false

// 等待刷新token的请求队列
let refreshSubscribers: Array<(token: string) => void> = []

// 添加请求到队列
function subscribeTokenRefresh(callback: (token: string) => void) {
  refreshSubscribers.push(callback)
}

// token刷新成功，通知所有等待的请求
function onTokenRefreshed(token: string) {
  refreshSubscribers.forEach(callback => callback(token))
  refreshSubscribers = []
}

// token刷新失败，清空队列
function onTokenRefreshFailed() {
  refreshSubscribers = []
}

// 创建axios实例
const service: AxiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL || '/api',
  timeout: parseInt(import.meta.env.VITE_API_TIMEOUT) || 30000,
  headers: {
    'Content-Type': 'application/json'
  }
})

// 请求拦截器
service.interceptors.request.use(
  (config: any) => {
    const userStore = useUserStore()
    
    // 添加认证token
    if (userStore.token) {
      config.headers = {
        ...config.headers,
        Authorization: `Bearer ${userStore.token}`
      }
      
      // 🔧 调试日志：显示当前使用的token
      const url = String(config.url || '')
      if (import.meta.env.MODE !== 'production' && !url.includes('/auth/login')) {
        console.log(`🔑 请求使用token: ${userStore.token.substring(0, 8)}... => ${config.method?.toUpperCase()} ${url}`)
      }
    } else {
      const url = String(config.url || '')
      if (import.meta.env.MODE !== 'production' && !url.includes('/auth/login')) {
        console.warn(`⚠️ 请求无token: ${config.method?.toUpperCase()} ${url}`)
      }
    }
    
    // 添加会话ID，便于后端刷新/登出更新会话
    if (userStore.sessionId) {
      config.headers = {
        ...config.headers,
        'X-Session-Id': userStore.sessionId
      }
    }
    
    // 添加租户ID (如果启用租户功能)
    if (import.meta.env.VITE_TENANT_ENABLED === 'true') {
      // 优先使用用户信息中的租户ID
      let tenantId = userStore.userInfo?.tenantId
      
      // 如果用户信息中没有租户ID（如登录时），尝试从以下来源获取：
      if (!tenantId) {
        // 1. 从请求数据中获取 (用于登录请求)
        if (config.data && typeof config.data === 'object' && config.data.tenantId) {
          tenantId = config.data.tenantId
        }
        // 2. 从localStorage获取保存的租户ID
        else {
          tenantId = localStorage.getItem('kexio-tenant-id') || 'default'
        }
      }
      
      // 添加租户头
      if (tenantId) {
        config.headers = {
          ...config.headers,
          'X-Tenant-Id': tenantId
        }
      }
    }
    
    // 添加请求时间戳
    config.headers = {
      ...config.headers,
      'X-Request-Time': Date.now().toString()
    }
    
    // 详细请求日志（仅开发环境）
    try {
      const url = String(config.url || '')
      const method = String(config.method || 'GET').toUpperCase()
      if (import.meta.env.MODE !== 'production') {
        const maskedAuth = (config.headers as any)?.Authorization ? 'present' : 'absent'
        const tag = url.includes('/menus') ? '[HTTP][menus][request]' : '[HTTP][request]'
        console.groupCollapsed(`${tag} ${method} ${url}`)
        console.log('headers:', { ...config.headers, Authorization: maskedAuth })
        if (config.params) console.log('params:', config.params)
        if (config.data) console.log('data:', config.data)
        console.groupEnd()
      }
    } catch {}
    
    return config
  },
  (error: AxiosError) => {
    console.error('Request Error:', error)
    return Promise.reject(error)
  }
)

// 响应拦截器
service.interceptors.response.use(
  (response: AxiosResponse<ApiResponse>) => {
    // 如果是blob类型响应（文件下载），直接返回原始数据
    if (response.config.responseType === 'blob') {
      return response.data as any
    }
    
    // 详细响应日志（仅开发环境）
    try {
      const url = String(response.config?.url || '')
      const method = String(response.config?.method || 'GET').toUpperCase()
      if (import.meta.env.MODE !== 'production') {
        const tag = url.includes('/menus') ? '[HTTP][menus][response]' : '[HTTP][response]'
        console.groupCollapsed(`${tag} ${method} ${url} -> ${response.status}`)
        console.log('body:', response.data)
        console.groupEnd()
      }
    } catch {}
    
    // 兼容后端直接返回原始布尔/字符串/对象的情况（非统一Result包裹）
    if (response && (typeof response.data !== 'object' || response.data === null || typeof (response.data as any).code === 'undefined')) {
      return {
        code: 200,
        message: 'OK',
        data: response.data as any,
        success: true,
        timestamp: Date.now()
      } as ApiResponse
    }
    const { code, message, data, success } = response.data
    
    // 业务成功
    if (success || code === 200) {
      return response.data
    }
    
    // 业务失败
    if (code !== 200) {
      ElMessage.error(message || '请求失败')
      return Promise.reject(new Error(message || '请求失败'))
    }
    
    return response.data
  },
  (error: AxiosError) => {
    const { response, message } = error
    const userStore = useUserStore()
    
    // 401错误在刷新token时不打印详细日志（避免控制台噪音）
    const is401 = response?.status === 401
    const shouldSuppressLog = is401 && isRefreshing
    
    // 详细错误日志（仅开发环境，且非token刷新中的401）
    if (!shouldSuppressLog) {
      try {
        const resp: any = (error as any)?.response
        const url = String(resp?.config?.url || '')
        const method = String(resp?.config?.method || 'GET').toUpperCase()
        if (import.meta.env.MODE !== 'production') {
          const tag = url.includes('/menus') ? '[HTTP][menus][error]' : '[HTTP][error]'
          console.groupCollapsed(`${tag} ${method} ${url} -> ${resp?.status || 'N/A'}`)
          console.log('error:', error?.message)
          if (resp?.data) console.log('body:', resp.data)
          console.groupEnd()
        }
      } catch {}
      
      // 非token刷新相关的错误才打印
      if (!is401 || !isRefreshing) {
        console.error('Response Error:', error)
      }
    }
    
    if (response) {
      const { status, data } = response as AxiosResponse<ApiResponse>
      
      switch (status) {
        case 400:
          ElMessage.error(data?.message || '请求参数错误')
          break
          
        case 401: {
          const originalRequest = response.config as any
          
          // 避免对刷新接口本身造成死循环
          const isRefreshCall = typeof originalRequest?.url === 'string' && originalRequest.url.includes('/auth/refresh')
          if (isRefreshCall) {
            // 刷新token失败，只提示一次
            if (!isRefreshing) {
              ElMessage.error('登录已过期，请重新登录')
            }
            isRefreshing = false
            onTokenRefreshFailed()
            userStore.forceLogout()
            router.push('/login')
            return Promise.reject(error)
          }
          
          // 如果没有refreshToken，直接登出
          if (!userStore.refreshToken) {
            if (!isRefreshing) {
              ElMessage.error('认证失败，请重新登录')
            }
            userStore.forceLogout()
            router.push('/login')
            return Promise.reject(error)
          }
          
          // 如果正在刷新token，将请求加入队列
          if (isRefreshing) {
            return new Promise((resolve) => {
              subscribeTokenRefresh((token: string) => {
                // 更新请求的token
                if (originalRequest.headers) {
                  originalRequest.headers.Authorization = `Bearer ${token}`
                }
                // 重试请求
                resolve(service(originalRequest))
              })
            })
          }
          
          // 标记为正在刷新，开始刷新token
          originalRequest._retry = true
          isRefreshing = true
          
          return userStore
            .refreshUserToken()
            .then(() => {
              const newToken = userStore.token
              // 通知所有等待的请求
              onTokenRefreshed(newToken)
              isRefreshing = false
              
              // 更新当前请求的token
              if (originalRequest.headers) {
                originalRequest.headers.Authorization = `Bearer ${newToken}`
              }
              // 重试当前请求
              return service(originalRequest)
            })
            .catch((err) => {
              // 刷新失败，只提示一次
              if (isRefreshing) {
                ElMessage.error('登录已过期，请重新登录')
              }
              isRefreshing = false
              onTokenRefreshFailed()
              userStore.forceLogout()
              router.push('/login')
              return Promise.reject(err)
            })
        }
          
          
        case 403:
          ElMessage.error('访问被拒绝，权限不足')
          break
          
        case 404:
          ElMessage.error('请求的资源不存在')
          break
          
        case 422:
          ElMessage.error(data?.message || '请求参数验证失败')
          break
          
        case 429:
          ElMessage.error('请求过于频繁，请稍后再试')
          break
          
        case 500:
          ElMessage.error('服务器内部错误')
          break
          
        case 502:
          ElMessage.error('网关错误')
          break
          
        case 503:
          ElMessage.error('服务暂时不可用')
          break
          
        case 504:
          ElMessage.error('网关超时')
          break
          
        default:
          ElMessage.error(data?.message || `请求失败 (${status})`)
          break
      }
    } else if (message.includes('timeout')) {
      ElMessage.error('请求超时，请稍后再试')
    } else if (message.includes('Network Error')) {
      ElMessage.error('网络连接错误，请检查网络')
    } else {
      ElMessage.error('请求失败，请稍后再试')
    }
    
    return Promise.reject(error)
  }
)

// 通用请求方法
const request = {
  get: <T = any>(url: string, config?: AxiosRequestConfig): Promise<ApiResponse<T>> => {
    return service.get(url, config)
  },
  
  post: <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ApiResponse<T>> => {
    return service.post(url, data, config)
  },
  
  put: <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ApiResponse<T>> => {
    return service.put(url, data, config)
  },
  
  delete: <T = any>(url: string, config?: AxiosRequestConfig): Promise<ApiResponse<T>> => {
    return service.delete(url, config)
  },
  
  patch: <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ApiResponse<T>> => {
    return service.patch(url, data, config)
  },

  /**
   * 下载文件（自动处理blob并触发下载）
   * @param options 下载配置
   * @example
   * // API层定义
   * export const exportUsers = (params) => {
   *   return request.download({ url: '/users/export', params, filename: '用户列表' })
   * }
   * 
   * // 组件中使用
   * await exportUsers(queryParams)
   */
  download: async (options: {
    url: string
    params?: any
    data?: any
    method?: 'get' | 'post'
    filename?: string
    showMessage?: boolean
  }): Promise<void> => {
    const {
      url,
      params,
      data,
      method = 'get',
      filename,
      showMessage = true
    } = options

    try {
      if (showMessage) {
        ElMessage.info('正在下载文件...')
      }

      // 发起请求
      let blob: Blob
      if (method === 'post') {
        blob = await service.post(url, data, {
          params,
          responseType: 'blob'
        })
      } else {
        blob = await service.get(url, {
          params,
          responseType: 'blob'
        })
      }

      // 检查是否是错误响应
      if (blob.type === 'application/json') {
        const text = await blob.text()
        const error = JSON.parse(text)
        throw new Error(error.message || '下载失败')
      }

      // 生成文件名
      let downloadFilename = filename || `download_${Date.now()}`
      if (!downloadFilename.includes('.')) {
        downloadFilename += '.xlsx'
      }

      // 创建下载链接
      const downloadUrl = window.URL.createObjectURL(blob)
      const link = document.createElement('a')
      link.href = downloadUrl
      link.download = downloadFilename
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
      window.URL.revokeObjectURL(downloadUrl)

      if (showMessage) {
        ElMessage.success('下载成功')
      }
    } catch (error: any) {
      console.error('下载失败:', error)
      ElMessage.error(error?.message || '下载失败')
      throw error
    }
  },

  /**
   * 上传文件
   * @param options 上传配置
   * @example
   * // API层定义
   * export const importUsers = (file, updateSupport = false) => {
   *   const formData = new FormData()
   *   formData.append('file', file)
   *   formData.append('updateSupport', String(updateSupport))
   *   return request.upload({ url: '/users/import', data: formData })
   * }
   * 
   * // 组件中使用
   * const result = await importUsers(file, true)
   */
  upload: async <T = any>(options: {
    url: string
    data: FormData
    onProgress?: (percent: number) => void
    showMessage?: boolean
  }): Promise<ApiResponse<T>> => {
    const {
      url,
      data,
      onProgress,
      showMessage = true
    } = options

    try {
      if (showMessage) {
        ElMessage.info('正在上传文件...')
      }

      const response = await service.post<T>(url, data, {
        headers: {
          'Content-Type': 'multipart/form-data'
        },
        onUploadProgress: onProgress ? (progressEvent: any) => {
          const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total)
          onProgress(percent)
        } : undefined
      }) as unknown as ApiResponse<T>

      if (showMessage && response.success) {
        ElMessage.success('上传成功')
      }

      return response
    } catch (error: any) {
      console.error('上传失败:', error)
      ElMessage.error(error?.message || '上传失败')
      throw error
    }
  }
}

// 文件上传方法
export const uploadFile = (url: string, formData: FormData, onUploadProgress?: (progressEvent: any) => void): Promise<ApiResponse> => {
  return service.post(url, formData, {
    headers: {
      'Content-Type': 'multipart/form-data'
    },
    onUploadProgress
  })
}

// 文件下载方法
export const downloadFile = (url: string, filename?: string, params?: any): Promise<void> => {
  return service.get(url, {
    params,
    responseType: 'blob'
  }).then((response: any) => {
    const blob = new Blob([response], {
      type: response.type || 'application/octet-stream'
    })
    
    const downloadUrl = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = downloadUrl
    link.download = filename || `download_${Date.now()}`
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(downloadUrl)
  })
}

// 批量请求方法
export const batchRequest = <T = any>(requests: Promise<ApiResponse<T>>[]): Promise<ApiResponse<T>[]> => {
  return Promise.allSettled(requests).then(results => {
    return results.map(result => {
      if (result.status === 'fulfilled') {
        return result.value
      } else {
        console.error('Batch request failed:', result.reason)
        return {
          code: 500,
          message: '请求失败',
          data: null,
          success: false,
          timestamp: Date.now()
        } as ApiResponse<T>
      }
    })
  })
}

// 重试请求方法
export const retryRequest = <T = any>(
  requestFn: () => Promise<ApiResponse<T>>,
  maxRetries: number = 3,
  delay: number = 1000
): Promise<ApiResponse<T>> => {
  return requestFn().catch(error => {
    if (maxRetries > 0) {
      return new Promise(resolve => {
        setTimeout(() => {
          resolve(retryRequest(requestFn, maxRetries - 1, delay * 2))
        }, delay)
      })
    }
    throw error
  })
}

// ==================== Excel 导入导出工具 ====================

/**
 * 导出Excel配置
 */
export interface ExportExcelOptions {
  /** API请求函数 */
  apiCall: () => Promise<any>
  /** 导出文件名（不含扩展名） */
  filename: string
  /** 加载提示信息 */
  loadingMessage?: string
  /** 成功提示信息 */
  successMessage?: string
  /** 是否显示加载提示 */
  showLoading?: boolean
  /** 是否显示成功提示 */
  showSuccess?: boolean
}

/**
 * 导入Excel配置
 */
export interface ImportExcelOptions {
  /** API请求函数 */
  apiCall: (file: File, updateSupport?: boolean) => Promise<any>
  /** 导入文件 */
  file: File
  /** 是否支持更新已存在的数据 */
  updateSupport?: boolean
  /** 加载提示信息 */
  loadingMessage?: string
  /** 成功提示信息 */
  successMessage?: string
  /** 是否显示加载提示 */
  showLoading?: boolean
  /** 是否显示成功提示 */
  showSuccess?: boolean
}

/**
 * 下载Excel模板配置
 */
export interface DownloadTemplateOptions {
  /** API请求函数 */
  apiCall: () => Promise<any>
  /** 模板文件名（不含扩展名） */
  filename: string
  /** 加载提示信息 */
  loadingMessage?: string
  /** 成功提示信息 */
  successMessage?: string
  /** 是否显示加载提示 */
  showLoading?: boolean
  /** 是否显示成功提示 */
  showSuccess?: boolean
}

/**
 * 导出Excel文件
 * @example
 * await exportExcel({
 *   apiCall: () => request.get('/users/export', { params, responseType: 'blob' }),
 *   filename: generateFilename('用户列表'),
 *   loadingMessage: '正在导出用户数据...'
 * })
 */
export async function exportExcel(options: ExportExcelOptions): Promise<void> {
  const {
    apiCall,
    filename,
    loadingMessage = '正在导出数据...',
    successMessage = '导出成功',
    showLoading = true,
    showSuccess = true
  } = options

  try {
    if (showLoading) {
      ElMessage.info(loadingMessage)
    }

    const blob = await apiCall()

    // 检查是否是错误响应（后端可能返回JSON错误）
    if (blob.type === 'application/json') {
      const text = await blob.text()
      const error = JSON.parse(text)
      throw new Error(error.message || '导出失败')
    }

    // 创建下载链接
    const url = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    link.download = `${filename}.xlsx`
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(url)

    if (showSuccess) {
      ElMessage.success(successMessage)
    }
  } catch (error: any) {
    console.error('导出失败:', error)
    ElMessage.error(error?.message || '导出失败')
    throw error
  }
}

/**
 * 导入Excel文件
 * @example
 * const result = await importExcel<ImportResult>({
 *   apiCall: (file, updateSupport) => userApi.importUsers(file, updateSupport),
 *   file: selectedFile,
 *   updateSupport: true
 * })
 */
export async function importExcel<T = any>(options: ImportExcelOptions): Promise<T> {
  const {
    apiCall,
    file,
    updateSupport = false,
    loadingMessage = '正在导入数据...',
    successMessage = '导入成功',
    showLoading = true,
    showSuccess = true
  } = options

  try {
    if (showLoading) {
      ElMessage.info(loadingMessage)
    }

    const response = await apiCall(file, updateSupport)
    const result = response.data

    if (showSuccess) {
      ElMessage.success(successMessage)
    }

    return result
  } catch (error: any) {
    console.error('导入失败:', error)
    ElMessage.error(error?.message || '导入失败')
    throw error
  }
}

/**
 * 下载Excel模板
 * @example
 * await downloadExcelTemplate({
 *   apiCall: () => request.get('/users/template', { responseType: 'blob' }),
 *   filename: '用户导入模板'
 * })
 */
export async function downloadExcelTemplate(options: DownloadTemplateOptions): Promise<void> {
  const {
    apiCall,
    filename,
    loadingMessage = '正在下载模板...',
    successMessage = '模板下载成功',
    showLoading = false,
    showSuccess = true
  } = options

  try {
    if (showLoading) {
      ElMessage.info(loadingMessage)
    }

    const blob = await apiCall()

    // 检查是否是错误响应
    if (blob.type === 'application/json') {
      const text = await blob.text()
      const error = JSON.parse(text)
      throw new Error(error.message || '下载模板失败')
    }

    // 创建下载链接
    const url = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    link.download = `${filename}.xlsx`
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(url)

    if (showSuccess) {
      ElMessage.success(successMessage)
    }
  } catch (error: any) {
    console.error('下载模板失败:', error)
    ElMessage.error(error?.message || '下载模板失败')
    throw error
  }
}

/**
 * 生成带时间戳的文件名
 * @param prefix 文件名前缀
 * @param format 日期格式 'date' | 'datetime' | 'timestamp'
 * @example
 * generateFilename('用户列表')           // 用户列表_2025-10-28
 * generateFilename('日志', 'datetime')   // 日志_2025-10-28_143052
 * generateFilename('数据', 'timestamp')  // 数据_1730097052123
 */
export function generateFilename(
  prefix: string,
  format: 'date' | 'datetime' | 'timestamp' = 'date'
): string {
  const now = new Date()

  switch (format) {
    case 'date':
      return `${prefix}_${now.toISOString().slice(0, 10)}`
    case 'datetime':
      return `${prefix}_${now.toISOString().slice(0, 10)}_${now.toTimeString().slice(0, 8).replace(/:/g, '')}`
    case 'timestamp':
      return `${prefix}_${now.getTime()}`
    default:
      return `${prefix}_${now.toISOString().slice(0, 10)}`
  }
}

/**
 * 验证文件类型
 * @param file 文件对象
 * @param allowedTypes 允许的MIME类型数组
 */
export function validateFileType(file: File, allowedTypes: string[]): boolean {
  return allowedTypes.includes(file.type)
}

/**
 * 验证文件大小
 * @param file 文件对象
 * @param maxSizeMB 最大文件大小（MB）
 */
export function validateFileSize(file: File, maxSizeMB: number): boolean {
  const maxSizeBytes = maxSizeMB * 1024 * 1024
  return file.size <= maxSizeBytes
}

/**
 * 验证Excel文件
 * @param file 文件对象
 * @param maxSizeMB 最大文件大小（MB），默认10MB
 * @example
 * const result = validateExcelFile(file)
 * if (!result.valid) {
 *   ElMessage.error(result.message)
 *   return
 * }
 */
export function validateExcelFile(
  file: File,
  maxSizeMB: number = 10
): { valid: boolean; message?: string } {
  // 验证文件类型
  const allowedTypes = [
    'application/vnd.ms-excel',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
  ]

  if (!validateFileType(file, allowedTypes)) {
    return {
      valid: false,
      message: '只能上传 .xls 或 .xlsx 格式的文件'
    }
  }

  // 验证文件大小
  if (!validateFileSize(file, maxSizeMB)) {
    return {
      valid: false,
      message: `文件大小不能超过 ${maxSizeMB}MB`
    }
  }

  return { valid: true }
}

export default request
